using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.Web;
using System.Xml;

using Migration.Classes;
using Migration.Migration;
using Migration.PublicControls;

using Telerik.Sitefinity;
using Telerik.Sitefinity.Abstractions;
using Telerik.Sitefinity.Configuration;
using Telerik.Sitefinity.Modules.Pages.Configuration;
using Telerik.Sitefinity.Services;
using Telerik.Sitefinity.GenericContent.Model;

namespace Migration
{
	/// <summary>
	/// 
	/// </summary>
	public class MigrationModule : ModuleBase
	{
		#region Fields

		public static readonly Guid landingPageId = new Guid("7994C8E1-6C95-4ECD-AFEA-E436ECF61A0D");
		public static readonly Guid subPageId = new Guid("ADF63708-1931-4794-BC7E-49E27C05CD0C");

		private MigrationExportServiceClient m_ExportClient;

		private delegate bool DelegateMigrationMethod();
		private delegate Message DelegateNoParameterWebMethod();
		private delegate Message DelegateOneParameterWebMethod(Message param);
		Dictionary<string, DelegateMigrationMethod> m_ImportMethods;
		List<Telerik.Sitefinity.Services.Migration.MigrationProvider> m_MigrationContentProviders;

		private XmlDocument m_XmlDocument;
		private XmlNamespaceManager m_XmlNamespaceManager;

		#endregion

		#region Module specific

		public const string ModuleName = "Migration";
		/// <summary>
		/// Gets the CLR types of all data managers provided by this module.
		/// </summary>
		/// <value>An array of <see cref="T:System.Type"/> objects.</value>
		public override Type[] Managers
		{
			get
			{
				return null;
			}
		}

		/// <summary>
		/// Initializes the service with specified settings.
		/// </summary>
		/// <param name="settings">The settings.</param>
		public override void Initialize(ModuleSettings settings)
		{
			base.Initialize(settings);
		}

		public override Guid LandingPageId
		{
			get
			{
				return MigrationModule.landingPageId;
			}
		}
		public Guid SubPageId
		{
			get
			{
				return MigrationModule.subPageId;
			}
		}

		/// <summary>
		/// Installs this module in Sitefinity system.
		/// </summary>
		/// <param name="initializer">The Site Initializer. A helper class for installing Sitefinity modules.</param>
		public override void Install(SiteInitializer initializer)
		{
			// Add the Migration Page Group to the Backend Taxonomy (if it doesn't already exist)
			using (var sf = App.WorkWith())
			{
				sf.Page().PageManager.Provider.SuppressSecurityChecks = true;

                var moduleNode = sf.Page(SiteInitializer.ModulesNodeId).Get();

				var migrationNode = sf.Pages().Where(p => p.Id == this.LandingPageId).Get().SingleOrDefault();
				if (migrationNode == null)
				{
					sf.Page().CreateNewPageGroup(moduleNode, this.LandingPageId).Do(p =>
					{
						p.Name = "Migration";
						p.UrlName = "Migration";
						p.ShowInNavigation = true;
						p.Attributes["ModuleName"] = "Migration";
						p.Title = "Migration";
						p.UrlName = "Migration";
					});
				}

				// Create the subpage
				var subPage = sf.Pages().Where(p => p.Id == this.SubPageId).Get().SingleOrDefault();
				if (subPage == null)
				{
					sf.Page().CreateNewStandardPage(this.LandingPageId, this.SubPageId).Do(p =>
					{
						p.Name = "Migration";
						p.UrlName = "Migration";
						p.Description = "Migration Tool";
						p.ShowInNavigation = false;
						p.Attributes["ModuleName"] = "Migration";
					}).CheckOut()
							.Do(draft => draft.TemplateId = sf.Page().PageManager.GetTemplates().Where(t => t.Name == SiteInitializer.BackendTemplateName).SingleOrDefault().Id)
							.Control().CreateNew(new BackendOverviewControl(), "Content").Done()
							.Publish();
				}
			}
		}

		protected override ConfigSection GetModuleConfig()
		{
			return null;
		}

		public override void Upgrade(SiteInitializer initializer, Version upgradeFrom)
		{
		}

		#endregion

		#region Constructor

		public MigrationModule()
		{
			m_XmlDocument = new XmlDocument();
			m_XmlNamespaceManager = new XmlNamespaceManager(m_XmlDocument.NameTable);
			m_XmlNamespaceManager.AddNamespace("ex", "http://schemas.datacontract.org/2004/07/System.ServiceModel");
		}

		#endregion

		#region CheckIfMigrationCancelled

		private void CheckIfMigrationCancelled()
		{
			var isCancelled = false;
			var resolvedPath = HttpContext.Current.Server.MapPath("~/App_Data/Sitefinity/Logs/MigrationCancel.txt");

			if (File.Exists(resolvedPath))
			{
				// Don't lock the file when reading it
				var fs = new FileStream(resolvedPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
				var sr = new StreamReader(fs);
				var fileContents = sr.ReadToEnd();
				sr.Close();

				if (fileContents == "CANCELLED")
					isCancelled = true;
			}

			MigrationSettings.MigrationCancelled = isCancelled;
		}

		#endregion

		#region GetFaultMessageDetails

		private Dictionary<string, string> GetFaultMessageDetails(Message m)
		{
			var result = new Dictionary<string, string>();

			m_XmlDocument.LoadXml(m.ToString());
			var nodeMessage = m_XmlDocument.SelectSingleNode("//ex:ExceptionDetail/ex:Message", m_XmlNamespaceManager);
			var nodeStackTrace = m_XmlDocument.SelectSingleNode("//ex:ExceptionDetail/ex:StackTrace", m_XmlNamespaceManager);
			result["Message"] = nodeMessage.InnerText;
			result["StackTrace"] = nodeStackTrace.InnerText;

			return result;
		}

		#endregion

		#region InitServiceClient

		private bool InitServiceClient(string sourceUrl)
		{
			if (!sourceUrl.EndsWith("/")) sourceUrl += "/";

			var binding = new BasicHttpBinding
			{
				/* SendTimeout = new TimeSpan(2), */
				// Uncomment to simulate TimeoutException
				OpenTimeout = new TimeSpan(1, 0, 0),
				ReceiveTimeout = new TimeSpan(1, 0, 0),
				SendTimeout = new TimeSpan(1, 0, 0),
				MaxReceivedMessageSize = 2147483647,
				MaxBufferSize = 2147483647,
				ReaderQuotas =
				{
					MaxStringContentLength = 2147483647,
					MaxArrayLength = 2147483647
				}
			};
			var sourceEndpoint = new EndpointAddress(sourceUrl + "MigrationExportService.svc");

			m_ExportClient = new MigrationExportServiceClient(binding, sourceEndpoint);

			try
			{
				m_ExportClient.Ping();
			}
			catch (TimeoutException)
			{
				MigrationLogger.AppendLogMessage("<b class=\"ErrorMessage\">Migration export service exists but timed out.</b>");
				return false;
			}
			catch (EndpointNotFoundException)
			{
				MigrationLogger.AppendLogMessage(String.Format("<b class=\"ErrorMessage\">Error:</b> Could not find <b>{0}</b> on the source site.<br/>", sourceEndpoint.Uri.AbsoluteUri));
				return false;
			}
			catch (CommunicationException ex)
			{
				MigrationLogger.AppendLogMessage(String.Format("<b class=\"ErrorMessage\">Error:</b> Could not find <b>{0}</b> on the source site.<br/>Error details:<br/><pre>{1}</pre>", sourceEndpoint.Uri.AbsoluteUri, ex.Message));
				return false;
			}

			return true;
		}

		#endregion

		#region GetContentCounts

		public Telerik.Sitefinity.Services.Migration.MigrationItemStatistics GetContentStatistics()
		{
			Message m;

			MigrationLogger.AppendLogMessage("<b>Getting content counts...</b><br/><br/>");

			try
			{
				m = m_ExportClient.GetMigrationStatistics();
			}
			catch (TimeoutException)
			{
				MigrationLogger.AppendLogMessage("<b class=\"ErrorMessage\">Service timed out</b><br/>");
				return null;
			}
			catch (CommunicationException ex)
			{
				MigrationLogger.AppendLogMessage(String.Format("<b class=\"ErrorMessage\">Communication error:</b><br/><pre>{0}<br/>{1}</pre>", ex.Message, ex.StackTrace));
				return null;
			}

			if (m.IsFault)
			{
				var exceptionDetails = GetFaultMessageDetails(m);
				MigrationLogger.AppendLogMessage(String.Format("<b class=\"ErrorMessage\">Error retrieving content counts:</b><br/><pre>{0}<br/>{1}</pre>", exceptionDetails["Message"], exceptionDetails["StackTrace"]));
				return null;
			}

			Telerik.Sitefinity.Services.Migration.MigrationItemStatistics mic;

			try
			{
				mic = m.GetBody<Telerik.Sitefinity.Services.Migration.MigrationItemStatistics>();
			}
			catch (SerializationException ex)
			{
				MigrationLogger.AppendLogMessage(String.Format("<b class=\"ErrorMessage\">Failed with exception:</b><br/><pre>{0}<br/>{1}</pre>", ex.Message, ex.StackTrace));
				return null;
			}

			return mic;
		}

		#endregion

		#region CallWebMethod

		private Message CallWebMethod(DelegateNoParameterWebMethod callMethod, string retrievedContent)
		{
			Message result;

			try
			{
				result = callMethod();
			}
			catch (TimeoutException)
			{
				MigrationLogger.AppendLogMessage("<b class=\"ErrorMessage\">Service timed out</b><br/>");
				return null;
			}
			catch (CommunicationException ex)
			{
				MigrationLogger.AppendLogMessage(String.Format("<b class=\"ErrorMessage\">Communication error:</b><br/><pre>{0}<br/>{1}</pre>", ex.Message, ex.StackTrace));
				return null;
			}

			if (result.IsFault)
			{
				var exceptionDetails = GetFaultMessageDetails(result);
				MigrationLogger.AppendLogMessage(String.Format("<b class=\"ErrorMessage\">Error retrieving {0}:</b><br/><pre>{1}<br/>{2}</pre>", retrievedContent, exceptionDetails["Message"], exceptionDetails["StackTrace"]));
				return null;
			}

			return result;
		}

		private Message CallWebMethod(DelegateOneParameterWebMethod callMethod, Message param, string retrievedContent)
		{
			Message result;

			try
			{
				result = callMethod(param);
			}
			catch (TimeoutException)
			{
				MigrationLogger.AppendLogMessage("<b class=\"ErrorMessage\">Service timed out</b><br/>");
				return null;
			}
			catch (CommunicationException ex)
			{
				MigrationLogger.AppendLogMessage(String.Format("<b class=\"ErrorMessage\">Communication error:</b><br/><pre>{0}<br/>{1}</pre>", ex.Message, ex.StackTrace));
				return null;
			}

			if (result.IsFault)
			{
				var exceptionDetails = GetFaultMessageDetails(result);
				MigrationLogger.AppendLogMessage(String.Format("<b class=\"ErrorMessage\">Error retrieving {0}:</b><br/><pre>{1}<br/>{2}</pre>", retrievedContent, exceptionDetails["Message"], exceptionDetails["StackTrace"]));
				return null;
			}

			return result;
		}

		#endregion

		#region ImportRoles

		private bool ImportRoles()
		{
			MigrationLogger.AppendLogMessage(String.Format("<b>Importing {0} role(s)...</b><br/>", MigrationStatistics.RolesCount));

			Message m = CallWebMethod(m_ExportClient.GetRoles, "role(s)");
			if (m == null)
				return false;

			List<Telerik.Sitefinity.Services.Migration.MigrationRole> rolesContents;

			try
			{
				rolesContents = m.GetBody<List<Telerik.Sitefinity.Services.Migration.MigrationRole>>();
			}
			catch (SerializationException ex)
			{
				MigrationLogger.AppendLogMessage(String.Format("<b class=\"ErrorMessage\">Failed with exception:</b><br/><pre>{0}<br/>{1}</pre>", ex.Message, ex.StackTrace));
				return false;
			}

			try
			{
				MigrationRoles.ImportRoles(rolesContents);
			}
			catch (Exception ex)
			{
				MigrationLogger.AppendLogMessage(String.Format("<b class=\"ErrorMessage\">Error migrating roles:</b><br/><pre>{0}<br/>{1}</pre>", ex.Message, ex.StackTrace));
				MigrationLogger.AppendNewLine();
				return false;
			}

			MigrationLogger.AppendNewLine();

			return true;
		}

		#endregion

		#region ImportUsers

		private bool ImportUsers()
		{
			MigrationLogger.AppendLogMessage(String.Format("<b>Importing {0} user(s)...</b><br/>", MigrationStatistics.UsersCount));

			Message m = CallWebMethod(m_ExportClient.GetUsersList, "users");
			if (m == null)
				return false;

			List<Telerik.Sitefinity.Services.Migration.MigrationItemContentDefinition> usersList;

			try
			{
				usersList = m.GetBody<List<Telerik.Sitefinity.Services.Migration.MigrationItemContentDefinition>>();
			}
			catch (SerializationException ex)
			{
				MigrationLogger.AppendLogMessage(String.Format("<b class=\"ErrorMessage\">Failed with exception:</b><br/><pre>{0}<br/>{1}</pre>", ex.Message, ex.StackTrace));
				return false;
			}

			foreach (var userListItem in usersList)
			{
				var param = Message.CreateMessage(m.Version, "http://tempuri.org/IMigrationExportService/GetSingleUser", userListItem);

				Message userMessage = CallWebMethod(m_ExportClient.GetSingleUser, param, "user");
				if (userMessage == null)
					return false;

				Telerik.Sitefinity.Services.Migration.MigrationUser userContent;

				try
				{
					userContent = userMessage.GetBody<Telerik.Sitefinity.Services.Migration.MigrationUser>();
				}
				catch (SerializationException ex)
				{
					MigrationLogger.AppendLogMessage(String.Format("<b class=\"ErrorMessage\">Failed with exception:</b><br/><pre>{0}<br/>{1}</pre>", ex.Message, ex.StackTrace));
					return false;
				}

				try
				{
					MigrationUsers.ImportUser(userContent);
				}
				catch (Exception ex)
				{
					MigrationLogger.AppendLogMessage(String.Format("<b class=\"ErrorMessage\">Error migrating user {0}:</b><br/><pre>{1}<br/>{2}</pre>", userContent.Username, ex.Message, ex.StackTrace));
					MigrationLogger.AppendNewLine();
					continue;
				}

				MigrationLogger.AppendNewLine();

				CheckIfMigrationCancelled();
				if (MigrationSettings.MigrationCancelled)
				{
					MigrationLogger.AppendLogMessage("<br/><b>Migration cancelled.</b>");
					return true;
				}
			}

			MigrationLogger.AppendNewLine();

			return true;
		}

		#endregion

		#region ImportContentProviders

		private bool ImportContentProviders()
		{
			MigrationLogger.AppendLogMessage("<b>Importing metadata definitions...</b><br/>");

			Message m = CallWebMethod(m_ExportClient.GetContentProviders, "metaData definitions");
			if (m == null)
				return false;

			try
			{
				m_MigrationContentProviders = m.GetBody<List<Telerik.Sitefinity.Services.Migration.MigrationProvider>>();
			}
			catch (SerializationException ex)
			{
				MigrationLogger.AppendLogMessage(String.Format("<b class=\"ErrorMessage\">Failed with exception:</b><br/><pre>{0}<br/>{1}</pre>", ex.Message, ex.StackTrace));
				return false;
			}

			foreach (Telerik.Sitefinity.Services.Migration.MigrationProvider provider in m_MigrationContentProviders)
			{
				try
				{
					MigrationMetaDataDefinitions.ImportMetaDataFields(provider);
				}
				catch (Exception ex)
				{
					MigrationLogger.AppendLogMessage(String.Format("<b class=\"ErrorMessage\">Error importing metadata definitions for {0}:</b><br/><pre>{1}<br/>{2}</pre>", provider.Name, ex.Message, ex.StackTrace));
					MigrationLogger.AppendNewLine();
					continue;
				}

				MigrationLogger.AppendNewLine();

				CheckIfMigrationCancelled();
				if (MigrationSettings.MigrationCancelled)
				{
					MigrationLogger.AppendLogMessage("<br/><b>Migration cancelled.</b>");
					return true;
				}
			}

			MigrationLogger.AppendNewLine();

			return true;
		}

		#endregion

		#region ImportLibraries

		private bool ImportLibraries()
		{
			MigrationLogger.AppendLogMessage(String.Format("<b>Importing {0} image, {1} document and {2} video libraries...</b><br/>",
				MigrationStatistics.ImageLibrariesCount,
				MigrationStatistics.DocumentLibrariesCount,
				MigrationStatistics.VideoLibrariesCount));

			Message m = CallWebMethod(m_ExportClient.GetLibrariesList, "libraries");
			if (m == null)
				return false;

			List<Telerik.Sitefinity.Services.Migration.MigrationItemContentDefinition> librariesList;

			try
			{
				librariesList = m.GetBody<List<Telerik.Sitefinity.Services.Migration.MigrationItemContentDefinition>>();
			}
			catch (SerializationException ex)
			{
				MigrationLogger.AppendLogMessage(String.Format("<b class=\"ErrorMessage\">Failed with exception:</b><br/><pre>{0}<br/>{1}</pre>", ex.Message, ex.StackTrace));
				return false;
			}

			foreach (var librariesListItem in librariesList)
			{
				// Check if the library already exists
				var checkItem = MigrationLibraries.GetLibrary(librariesListItem.Id);
				if (checkItem != null && checkItem.Items.Where(i => i.Status == ContentLifecycleStatus.Master).Count() == librariesListItem.SubItemsCount)
				{
					MigrationLogger.AppendLogMessage(String.Format("Skipping \"<b>{0}</b>\", already exists.<br/>", checkItem.Title));
					continue;
				}

				var param = Message.CreateMessage(m.Version, "http://tempuri.org/IMigrationExportService/GetSingleLibrary", librariesListItem);

				Message libraryMessage = CallWebMethod(m_ExportClient.GetSingleLibrary, param, "library");
				if (libraryMessage == null)
					return false;

				Telerik.Sitefinity.Services.Migration.MigrationLibrary libraryContent;

				try
				{
					libraryContent = libraryMessage.GetBody<Telerik.Sitefinity.Services.Migration.MigrationLibrary>();
				}
				catch (SerializationException ex)
				{
					MigrationLogger.AppendLogMessage(String.Format("<b class=\"ErrorMessage\">Failed with exception:</b><br/><pre>{0}<br/>{1}</pre>", ex.Message, ex.StackTrace));
					return false;
				}

				//try
				//{
					MigrationLibraries.ImportLibrary(libraryContent, libraryContent.TypeName);
				//}
				//catch (Exception ex)
				//{
				//	MigrationLogger.AppendLogMessage(String.Format("<b class=\"ErrorMessage\">Error migrating library:</b><br/><pre>{0}<br/>{1}</pre>", ex.Message, ex.StackTrace));
				//	MigrationLogger.AppendNewLine();
				//	continue;
				//}

				MigrationLogger.AppendNewLine();

				CheckIfMigrationCancelled();
				if (MigrationSettings.MigrationCancelled)
				{
					MigrationLogger.AppendLogMessage("<br/><b>Migration cancelled.</b>");
					return true;
				}
			}

			MigrationLogger.AppendNewLine();

			return true;
		}

		#endregion

		#region ImportGenericContent

		private bool ImportGenericContent()
		{
			MigrationLogger.AppendLogMessage(String.Format("<b>Importing {0} generic content(s)...</b><br/>", MigrationStatistics.GenericContentsCount));

			Message m = CallWebMethod(m_ExportClient.GetGenericContentList, "generic content");
			if (m == null)
				return false;

			List<Telerik.Sitefinity.Services.Migration.MigrationItemContentDefinition> genericContentsList;

			try
			{
				genericContentsList = m.GetBody<List<Telerik.Sitefinity.Services.Migration.MigrationItemContentDefinition>>();
			}
			catch (SerializationException ex)
			{
				MigrationLogger.AppendLogMessage(String.Format("<b class=\"ErrorMessage\">Failed with exception:</b><br/><pre>{0}<br/>{1}</pre>", ex.Message, ex.StackTrace));
				return false;
			}

			foreach (var genericContentListItem in genericContentsList)
			{
				var param = Message.CreateMessage(m.Version, "http://tempuri.org/IMigrationExportService/GetSingleGenericContent", genericContentListItem);

				Message genericContentMessage = CallWebMethod(m_ExportClient.GetSingleGenericContent, param, "generic content");
				if (genericContentMessage == null)
					return false;				

				Telerik.Sitefinity.Services.Migration.MigrationGenericContent genericContent;

				try
				{
					genericContent = genericContentMessage.GetBody<Telerik.Sitefinity.Services.Migration.MigrationGenericContent>();
				}
				catch (SerializationException ex)
				{
					MigrationLogger.AppendLogMessage(String.Format("<b class=\"ErrorMessage\">Failed with exception:</b><br/><pre>{0}<br/>{1}</pre>", ex.Message, ex.StackTrace));
					return false;
				}

				try
				{
					MigrationGenericContents.ImportGenericContent(genericContent);
				}
				catch (Exception ex)
				{
					MigrationLogger.AppendLogMessage(String.Format("<b class=\"ErrorMessage\">Error migrating generic content:</b><br/><pre>{0}<br/>{1}</pre>", ex.Message, ex.StackTrace));
					MigrationLogger.AppendNewLine();
					continue;
				}

				MigrationLogger.AppendNewLine();

				CheckIfMigrationCancelled();
				if (MigrationSettings.MigrationCancelled)
				{
					MigrationLogger.AppendLogMessage("<br/><b>Migration cancelled.</b>");
					return true;
				}
			}

			MigrationLogger.AppendNewLine();

			return true;
		}

		#endregion

		#region ImportNews

		private bool ImportNews()
		{
			MigrationLogger.AppendLogMessage(String.Format("<b>Importing {0} news...</b><br/>", MigrationStatistics.NewsCount));

			Message m = CallWebMethod(m_ExportClient.GetNewsList, "news");
			if (m == null)
				return false;

			List<Telerik.Sitefinity.Services.Migration.MigrationItemContentDefinition> newsList;

			try
			{
				newsList = m.GetBody<List<Telerik.Sitefinity.Services.Migration.MigrationItemContentDefinition>>();
			}
			catch (SerializationException ex)
			{
				MigrationLogger.AppendLogMessage(String.Format("<b class=\"ErrorMessage\">Failed with exception:</b><br/><pre>{0}<br/>{1}</pre>", ex.Message, ex.StackTrace));
				return false;
			}

			foreach (var newsListItem in newsList)
			{
				var param = Message.CreateMessage(m.Version, "http://tempuri.org/IMigrationExportService/GetSingleNews", newsListItem);

				Message newsMessage = CallWebMethod(m_ExportClient.GetSingleNews, param, "news");
				if (newsMessage == null)
					return false;

				Telerik.Sitefinity.Services.Migration.MigrationGenericContent newsContent;

				try
				{
					newsContent = newsMessage.GetBody<Telerik.Sitefinity.Services.Migration.MigrationGenericContent>();
				}
				catch (SerializationException ex)
				{
					MigrationLogger.AppendLogMessage(String.Format("<b class=\"ErrorMessage\">Failed with exception:</b><br/><pre>{0}<br/>{1}</pre>", ex.Message, ex.StackTrace));
					return false;
				}

				try
				{
					MigrationNews.ImportNews(newsContent);
				}
				catch (Exception ex)
				{
					MigrationLogger.AppendLogMessage(String.Format("<b class=\"ErrorMessage\">Error migrating news:</b><br/><pre>{0}<br/>{1}</pre>", ex.Message, ex.StackTrace));
					MigrationLogger.AppendNewLine();
					continue;
				}

				MigrationLogger.AppendNewLine();

				CheckIfMigrationCancelled();
				if (MigrationSettings.MigrationCancelled)
				{
					MigrationLogger.AppendLogMessage("<br/><b>Migration cancelled.</b>");
					return true;
				}
			}

			MigrationLogger.AppendNewLine();

			return true;
		}

		#endregion

		#region ImportBlogs

		private bool ImportBlogs()
		{
			MigrationLogger.AppendLogMessage(String.Format("<b>Importing {0} blog(s) with {1} blog post(s)...</b><br/>", MigrationStatistics.BlogsCount, MigrationStatistics.BlogPostsCount));

			Message m = CallWebMethod(m_ExportClient.GetBlogsList, "blogs");
			if (m == null)
				return false;

			List<Telerik.Sitefinity.Services.Migration.MigrationItemContentDefinition> blogsList;

			try
			{
				blogsList = m.GetBody<List<Telerik.Sitefinity.Services.Migration.MigrationItemContentDefinition>>();
			}
			catch (SerializationException ex)
			{
				MigrationLogger.AppendLogMessage(String.Format("<b class=\"ErrorMessage\">Failed with exception:</b><br/><pre>{0}<br/>{1}</pre>", ex.Message, ex.StackTrace));
				return false;
			}

			foreach (var blogListItem in blogsList)
			{
				var param = Message.CreateMessage(m.Version, "http://tempuri.org/IMigrationExportService/GetSingleBlog", blogListItem);

				Message blogMessage = CallWebMethod(m_ExportClient.GetSingleBlog, param, "blog");
				if (blogMessage == null)
					return false;

				Telerik.Sitefinity.Services.Migration.MigrationBlog blogContent;

				try
				{
					blogContent = blogMessage.GetBody<Telerik.Sitefinity.Services.Migration.MigrationBlog>();
				}
				catch (SerializationException ex)
				{
					MigrationLogger.AppendLogMessage(String.Format("<b class=\"ErrorMessage\">Failed with exception:</b><br/><pre>{0}<br/>{1}</pre>", ex.Message, ex.StackTrace));
					return false;
				}

				try
				{
					MigrationBlogs.ImportBlog(blogContent);
				}
				catch (Exception ex)
				{
					MigrationLogger.AppendLogMessage(String.Format("<b class=\"ErrorMessage\">Error migrating blog:</b><br/><pre>{0}<br/>{1}</pre>", ex.Message, ex.StackTrace));
					MigrationLogger.AppendNewLine();
					continue;
				}

				MigrationLogger.AppendNewLine();

				CheckIfMigrationCancelled();
				if (MigrationSettings.MigrationCancelled)
				{
					MigrationLogger.AppendLogMessage("<br/><b>Migration cancelled.</b>");
					return true;
				}
			}

			return true;
		}

		#endregion

		#region ImportEvents

		private bool ImportEvents()
		{
			MigrationLogger.AppendLogMessage(String.Format("<b>Importing {0} event(s)...</b><br/>", MigrationStatistics.EventsCount));

			Message m = CallWebMethod(m_ExportClient.GetEventsList, "events");
			if (m == null)
				return false;

			List<Telerik.Sitefinity.Services.Migration.MigrationItemContentDefinition> eventsList;

			try
			{
				eventsList = m.GetBody<List<Telerik.Sitefinity.Services.Migration.MigrationItemContentDefinition>>();
			}
			catch (SerializationException ex)
			{
				MigrationLogger.AppendLogMessage(String.Format("<b class=\"ErrorMessage\">Failed with exception:</b><br/><pre>{0}<br/>{1}</pre>", ex.Message, ex.StackTrace));
				return false;
			}

			foreach (var eventListItem in eventsList)
			{
				var param = Message.CreateMessage(m.Version, "http://tempuri.org/IMigrationExportService/GetSingleEvent", eventListItem);

				Message eventMessage = CallWebMethod(m_ExportClient.GetSingleEvent, param, "event");
				if (eventMessage == null)
					return false;

				Telerik.Sitefinity.Services.Migration.MigrationEvent eventContent;

				try
				{
					eventContent = eventMessage.GetBody<Telerik.Sitefinity.Services.Migration.MigrationEvent>();
				}
				catch (SerializationException ex)
				{
					MigrationLogger.AppendLogMessage(String.Format("<b class=\"ErrorMessage\">Failed with exception:</b><br/><pre>{0}<br/>{1}</pre>", ex.Message, ex.StackTrace));
					return false;
				}

				try
				{
					MigrationEvents.ImportEvent(eventContent);
				}
				catch (Exception ex)
				{
					MigrationLogger.AppendLogMessage(String.Format("<b class=\"ErrorMessage\">Error migrating event:</b><br/><pre>{0}<br/>{1}</pre>", ex.Message, ex.StackTrace));
					MigrationLogger.AppendNewLine();
					continue;
				}

				MigrationLogger.AppendNewLine();

				CheckIfMigrationCancelled();
				if (MigrationSettings.MigrationCancelled)
				{
					MigrationLogger.AppendLogMessage("<br/><b>Migration cancelled.</b>");
					return true;
				}
			}

			MigrationLogger.AppendNewLine();

			return true;
		}

		#endregion

		#region ImportLists

		private bool ImportLists()
		{
			MigrationLogger.AppendLogMessage(String.Format("<b>Importing {0} list(s)...</b><br/>", MigrationStatistics.ListsCount));

			Message m = CallWebMethod(m_ExportClient.GetLists, "lists");
			if (m == null)
				return false;

			List<Telerik.Sitefinity.Services.Migration.MigrationList> listsContents;

			try
			{
				listsContents = m.GetBody<List<Telerik.Sitefinity.Services.Migration.MigrationList>>();
			}
			catch (SerializationException ex)
			{
				MigrationLogger.AppendLogMessage(String.Format("<b class=\"ErrorMessage\">Failed with exception:</b><br/><pre>{0}<br/>{1}</pre>", ex.Message, ex.StackTrace));
				return false;
			}

			foreach (var listContent in listsContents)
			{
				try
				{
					MigrationLists.ImportList(listContent);
				}
				catch (Exception ex)
				{
					MigrationLogger.AppendLogMessage(String.Format("<b class=\"ErrorMessage\">Error migrating list \"<b>{0}</b>\":</b><br/><pre>{0}<br/>{1}</pre>", ex.Message, ex.StackTrace));
					MigrationLogger.AppendNewLine();
					continue;
				}
			}

			MigrationLogger.AppendNewLine();

			return true;
		}

		#endregion

		#region ImportMasterPages

		private bool ImportMasterPages()
		{
			MigrationLogger.AppendLogMessage(String.Format("<b>Importing {0} master pages(s)...</b><br/>", MigrationStatistics.MasterPagesCount));

			Message m = CallWebMethod(m_ExportClient.GetMasterPagesList, "master pages");
			if (m == null)
				return false;

			List<Telerik.Sitefinity.Services.Migration.MigrationItemContentDefinition> masterPagesList;

			try
			{
				masterPagesList = m.GetBody<List<Telerik.Sitefinity.Services.Migration.MigrationItemContentDefinition>>();
			}
			catch (SerializationException ex)
			{
				MigrationLogger.AppendLogMessage(String.Format("<b class=\"ErrorMessage\">Failed with exception:</b><br/><pre>{0}<br/>{1}</pre>", ex.Message, ex.StackTrace));
				return false;
			}

			foreach (var masterPageItem in masterPagesList)
			{
				var param = Message.CreateMessage(m.Version, "http://tempuri.org/IMigrationExportService/GetSingleMasterPage", masterPageItem);

				Message masterPageMessage = CallWebMethod(m_ExportClient.GetSingleMasterPage, param, "master page");
				if (masterPageMessage == null)
					return false;

				Telerik.Sitefinity.Services.Migration.MigrationMasterPage masterPageContent;

				try
				{
					masterPageContent = masterPageMessage.GetBody<Telerik.Sitefinity.Services.Migration.MigrationMasterPage>();
				}
				catch (SerializationException ex)
				{
					MigrationLogger.AppendLogMessage(String.Format("<b class=\"ErrorMessage\">Failed with exception:</b><br/><pre>{0}<br/>{1}</pre>", ex.Message, ex.StackTrace));
					return false;
				}

				try
				{
					MigrationMasterPages.ImportMasterPage(masterPageContent);
				}
				catch (Exception ex)
				{
					MigrationLogger.AppendLogMessage(String.Format("<b class=\"ErrorMessage\">Error migrating master page:</b><br/><pre>{0}<br/>{1}</pre>", ex.Message, ex.StackTrace));
					MigrationLogger.AppendNewLine();
					continue;
				}

				MigrationLogger.AppendNewLine();

				CheckIfMigrationCancelled();
				if (MigrationSettings.MigrationCancelled)
				{
					MigrationLogger.AppendLogMessage("<br/><b>Migration cancelled.</b>");
					return true;
				}
			}

			MigrationLogger.AppendNewLine();

			return true;
		}

		#endregion

		#region ImportThemes

		private bool ImportThemes()
		{
			MigrationLogger.AppendLogMessage(String.Format("<b>Importing {0} theme(s)...</b><br/>", MigrationStatistics.ThemesCount));

			Message m = CallWebMethod(m_ExportClient.GetThemes, "themes");
			if (m == null)
				return false;

			List<Telerik.Sitefinity.Services.Migration.MigrationTheme> themesContents;

			try
			{
				themesContents = m.GetBody<List<Telerik.Sitefinity.Services.Migration.MigrationTheme>>();
			}
			catch (SerializationException ex)
			{
				MigrationLogger.AppendLogMessage(String.Format("<b class=\"ErrorMessage\">Failed with exception:</b><br/><pre>{0}<br/>{1}</pre>", ex.Message, ex.StackTrace));
				return false;
			}

			try
			{
				MigrationThemes.ImportThemes(themesContents);
			}
			catch (Exception ex)
			{
				MigrationLogger.AppendLogMessage(String.Format("<b class=\"ErrorMessage\">Error migrating themes:</b><br/><pre>{0}<br/>{1}</pre>", ex.Message, ex.StackTrace));
				MigrationLogger.AppendNewLine();
				return false;
			}

			MigrationLogger.AppendNewLine();

			CheckIfMigrationCancelled();
			if (MigrationSettings.MigrationCancelled)
			{
				MigrationLogger.AppendLogMessage("<br/><b>Migration cancelled.</b>");
			}

			return true;
		}

		#endregion

		#region ImportTemplates

		private bool ImportTemplates()
		{
			MigrationLogger.AppendLogMessage(String.Format("<b>Importing {0} template(s)...</b><br/>", MigrationStatistics.TemplatesCount));

			Message m = CallWebMethod(m_ExportClient.GetTemplatesList, "templates");
			if (m == null)
				return false;

			List<Telerik.Sitefinity.Services.Migration.MigrationItemContentDefinition> templatesList;

			try
			{
				templatesList = m.GetBody<List<Telerik.Sitefinity.Services.Migration.MigrationItemContentDefinition>>();
			}
			catch (SerializationException ex)
			{
				MigrationLogger.AppendLogMessage(String.Format("<b class=\"ErrorMessage\">Failed with exception:</b><br/><pre>{0}<br/>{1}</pre>", ex.Message, ex.StackTrace));
				return false;
			}

			foreach (var templateListItem in templatesList)
			{
				var param = Message.CreateMessage(m.Version, "http://tempuri.org/IMigrationExportService/GetSingleTemplate", templateListItem);

				Message templateMessage = CallWebMethod(m_ExportClient.GetSingleTemplate, param, "template");
				if (templateMessage == null)
					return false;

				Telerik.Sitefinity.Services.Migration.MigrationTemplate templateContent;

				try
				{
					templateContent = templateMessage.GetBody<Telerik.Sitefinity.Services.Migration.MigrationTemplate>();
				}
				catch (SerializationException ex)
				{
					MigrationLogger.AppendLogMessage(String.Format("<b class=\"ErrorMessage\">Failed with exception:</b><br/><pre>{0}<br/>{1}</pre>", ex.Message, ex.StackTrace));
					return false;
				}

				try
				{
					MigrationTemplates.ImportTemplate(templateContent);
				}
				catch (Exception ex)
				{
					MigrationLogger.AppendLogMessage(String.Format("<b class=\"ErrorMessage\">Error migrating template {0}:</b><br/><pre>{1}<br/>{2}</pre>", templateContent.Name, ex.Message, ex.StackTrace));
					MigrationLogger.AppendNewLine();
					continue;
				}

				MigrationLogger.AppendNewLine();

				CheckIfMigrationCancelled();
				if (MigrationSettings.MigrationCancelled)
				{
					MigrationLogger.AppendLogMessage("<br/><b>Migration cancelled.</b>");
					return true;
				}
			}

			return true;
		}		

		#endregion

		#region ImportPages

		private bool ImportPages()
		{
			MigrationLogger.AppendLogMessage(String.Format("<b>Importing {0} page(s)...</b><br/>", MigrationStatistics.PagesCount));

			Message m = CallWebMethod(m_ExportClient.GetPagesList, "pages");
			if (m == null)
				return false;

			List<Telerik.Sitefinity.Services.Migration.MigrationPageContentDefinition> pagesList;

			try
			{
				pagesList = m.GetBody<List<Telerik.Sitefinity.Services.Migration.MigrationPageContentDefinition>>();
			}
			catch (SerializationException ex)
			{
				MigrationLogger.AppendLogMessage(String.Format("<b class=\"ErrorMessage\">Failed with exception:</b><br/><pre>{0}<br/>{1}</pre>", ex.Message, ex.StackTrace));
				return false;
			}

			foreach (var pageListItem in pagesList)
			{
				var param = Message.CreateMessage(m.Version, "http://tempuri.org/IMigrationExportService/GetSinglePage", pageListItem);

				Message pageMessage = CallWebMethod(m_ExportClient.GetSinglePage, param, "page");
				if (pageMessage == null)
					return false;

				Telerik.Sitefinity.Services.Migration.MigrationPageGroup pageGroupContent;

				try
				{
					pageGroupContent = pageMessage.GetBody<Telerik.Sitefinity.Services.Migration.MigrationPageGroup>();
				}
				catch (SerializationException ex)
				{
					MigrationLogger.AppendLogMessage(String.Format("<b class=\"ErrorMessage\">Failed with exception:</b><br/><pre>{0}<br/>{1}</pre>", ex.Message, ex.StackTrace));
					return false;
				}

				try
				{
					MigrationPages.ImportPage(pageGroupContent);
				}
				catch (Exception ex)
				{
					MigrationLogger.AppendLogMessage(String.Format("<b class=\"ErrorMessage\">Error migrating page {0}:</b><br/><pre>{1}<br/>{2}</pre>", pageGroupContent.Pages[0].MenuName, ex.Message, ex.StackTrace));
					MigrationLogger.AppendNewLine();
					continue;
				}

				MigrationLogger.AppendNewLine();

				CheckIfMigrationCancelled();
				if (MigrationSettings.MigrationCancelled)
				{
					MigrationLogger.AppendLogMessage("<br/><b>Migration cancelled.</b>");
					return true;
				}
			}

			return true;
		}

		#endregion

		#region DoMigration

		public bool CheckService(string sourceUrl)
		{
			var endPointPresent = InitServiceClient(sourceUrl);
			if (!endPointPresent)
			{
				m_ExportClient.Close();
				return false;
			}

			return true;
		}

		public void DoMigration(string sourceUrl, string checkedModule)
		{
			m_ImportMethods = new Dictionary<string, DelegateMigrationMethod>
			{
				{ "Migrate_Roles", ImportRoles },
			    { "Migrate_Users", ImportUsers },
			    { "Migrate_MetaDataDefinitions", ImportContentProviders },
			    { "Migrate_Libraries", ImportLibraries },
				{ "Migrate_GenericContent", ImportGenericContent },
			    { "Migrate_News", ImportNews },
			    { "Migrate_Blogs", ImportBlogs },
			    { "Migrate_Events", ImportEvents },
			    { "Migrate_Lists", ImportLists },
				{ "Migrate_MasterPages", ImportMasterPages },
			    { "Migrate_Themes", ImportThemes },
			    { "Migrate_Templates", ImportTemplates },
			    { "Migrate_Pages", ImportPages }
			};

			m_ImportMethods[checkedModule]();
		}

		public void EndMigration()
		{
			MigrationLogger.AppendLogMessage("<b>Performing post migration actions...</b>");
			MigrationLogger.AppendNewLine();
			MigrationLogger.AppendNewLine();

			// Set the home page
			if (MigrationSettings.HomePageId != Guid.Empty)
			{
				var m_ConfigManager = ConfigManager.GetManager();
				var pagesConfig = m_ConfigManager.GetSection<PagesConfig>();
				pagesConfig.HomePageId = MigrationSettings.HomePageId;
				m_ConfigManager.SaveSection(pagesConfig);
			}

			string result = MigrationUrlRewriter.RewriteGenericContentItemsUrls();
			MigrationLogger.AppendLogMessage(result);
			MigrationLogger.AppendNewLine();

			result = MigrationUrlRewriter.RewriteNewsItemsUrls();
			MigrationLogger.AppendLogMessage(result);
			MigrationLogger.AppendNewLine();

			result = MigrationUrlRewriter.RewriteBlogItemsUrls();
			MigrationLogger.AppendLogMessage(result);
			MigrationLogger.AppendNewLine();

			result = MigrationUrlRewriter.RewriteEventItemsUrls();
			MigrationLogger.AppendLogMessage(result);
			MigrationLogger.AppendNewLine();

			result = MigrationUrlRewriter.RewriteTemplateUrls();
			MigrationLogger.AppendLogMessage(result);
			MigrationLogger.AppendNewLine();

			result = MigrationUrlRewriter.RewritePageUrls();
			MigrationLogger.AppendLogMessage(result);
			MigrationLogger.AppendNewLine();

			m_ExportClient.Close();
		}

		#endregion
	}
}